package ace.module.sms.core.impl.manager.impl;

import ace.cmp.core.constants.CoreConstant;
import ace.cmp.core.utils.SystemClockUtils;
import ace.cmp.data.spring.data.jdbc.querydsl.rsql.core.manager.spring.AbstractSpringDtoManager;
import ace.cmp.id.generator.api.LongIdGenerator;
import ace.cmp.json.api.JsonService;
import ace.module.sms.api.enums.SmsSendRecordStatusEnum;
import ace.module.sms.api.model.dto.SmsSendRecordDto;
import ace.module.sms.core.impl.dao.entity.QSmsSendRecord;
import ace.module.sms.core.impl.dao.entity.SmsApplication;
import ace.module.sms.core.impl.dao.entity.SmsSendRecord;
import ace.module.sms.core.impl.dao.entity.SmsSupplier;
import ace.module.sms.core.impl.dao.repository.SmsSendRecordRepository;
import ace.module.sms.core.impl.manager.SmsSendRecordManager;
import java.time.Instant;
import java.util.Map;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringSubstitutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * 短信发送记录 spring data jdbc querydsl rsql manager implement.
 *
 * @author Caspar
 */
@AllArgsConstructor
@Component
public class SmsSendRecordManagerImpl
    extends AbstractSpringDtoManager<SmsSendRecord, Long, SmsSendRecordDto>
    implements SmsSendRecordManager {
  private final SmsSendRecordRepository smsSendRecordRepository;
  private final LongIdGenerator idGenerator;
  private final JsonService jsonService;

  @Transactional(rollbackFor = Exception.class)
  @Override
  public SmsSendRecord addSendingRecord(
      SmsApplication smsApplication, SmsSupplier smsSupplier, String phoneNumber, String content) {
    Long smsApplicationId = smsApplication.getId();
    Long now = Instant.now().toEpochMilli();
    Long id = idGenerator.get();
    SmsSendRecord sendRecord =
        SmsSendRecord.builder()
            .id(id)
            .smsAppId(smsApplicationId)
            .identifier(id.toString())
            .supplierType(smsSupplier.getType())
            .planSendTime(now)
            .arrivalTime(now)
            .resultRemark(StringUtils.EMPTY)
            .phoneNumber(phoneNumber)
            .status(SmsSendRecordStatusEnum.SENDING.getCode())
            .content(content)
            .deleteFlag(CoreConstant.DELETE_FLAG_NOT)
            .createTime(now)
            .updateTime(now)
            .rowVersion(CoreConstant.DEFAULT_ROW_VERSION)
            .build();

    this.smsSendRecordRepository.insert(sendRecord);

    return sendRecord;
  }

  @Transactional(rollbackFor = Exception.class)
  @Override
  public void updateSuccess(Long id, String sendResultRemark) {
    QSmsSendRecord qSmsSendRecord = QSmsSendRecord.smsSendRecord;
    this.smsSendRecordRepository.update(
        query ->
            query
                .set(qSmsSendRecord.status, SmsSendRecordStatusEnum.SUCCESS.getCode())
                .set(qSmsSendRecord.resultRemark, sendResultRemark)
                .set(qSmsSendRecord.updateTime, SystemClockUtils.currentTimeMillis())
                .set(qSmsSendRecord.rowVersion, qSmsSendRecord.rowVersion.add(1))
                .where(qSmsSendRecord.id.eq(id))
                .execute());
  }

  @Transactional(rollbackFor = Exception.class)
  @Override
  public void updateFailure(Long id, String sendResultRemark) {
    QSmsSendRecord qSmsSendRecord = QSmsSendRecord.smsSendRecord;
    this.smsSendRecordRepository.update(
        query ->
            query
                .set(qSmsSendRecord.status, SmsSendRecordStatusEnum.FAILURE.getCode())
                .set(qSmsSendRecord.resultRemark, sendResultRemark)
                .set(qSmsSendRecord.updateTime, SystemClockUtils.currentTimeMillis())
                .set(qSmsSendRecord.rowVersion, qSmsSendRecord.rowVersion.add(1))
                .where(qSmsSendRecord.id.eq(id))
                .execute());
  }

  @Override
  public String transformSmsContent(String templateContent, Map<String, String> contentParams) {
    if (StringUtils.isNotEmpty(templateContent)) {
      return StringSubstitutor.replace(templateContent, contentParams);
    }
    return jsonService.toJson(contentParams);
  }
}
